/********************************************************************
	filename: 	Line2D.cpp
	created:	2010/04/16
	author:		Xiuwei Chen

	purpose:	Implement of class 2D line

	All rights Reserved
*********************************************************************/

#include "Line2D.h"

/// <Summary>
/// Zero of Line2D
/// </Summary>
const Line2D Line2D::Zero = Line2D(0, 0, 0);

/// <Summary>
/// default constructor
/// </Summary>
Line2D::Line2D()
{
	a = 0;
	b = 0;
	c = 0;
}

/// <Summary>
/// copy constructor
/// </Summary>
Line2D::Line2D(const Line2D &line)
	: a(line.a), b(line.b), c(line.c)
{
}

/// <Summary>
/// constructor
/// </Summary>
Line2D::Line2D(const Point2D &p0, const Point2D &p1)
	: a(p1.y - p0.y), b(p0.x - p1.x), c(p0.y * p1.x - p0.x * p1.y)
{
	if(a < 0)
	{
		a = -a;
		b = -b;
		c = -c;
	}
}

/// <Summary>
/// constructor
/// </Summary>
Line2D::Line2D(double _a, double _b, double _c)
	: a(_a), b(_b), c(_c)
{
	if(_a < 0)
	{
		a = -_a;
		b = -_b;
		c = -_c;
	}
}

/// <Summary>
/// set value
/// </Summary>
void Line2D::SetValue(double _a, double _b, double _c)
{
	a = _a;
	b = _b;
	c = _c;
}

/// <Summary>
/// overload operation: assignment
/// </Summary>
Line2D & Line2D::operator = (const Line2D &line)
{
	a = line.a;
	b = line.b;
	c = line.c;
	return *this;
}

/// <Summary>
/// overload operation: "==". simple compare, not normalize
/// </Summary>
bool Line2D::operator == (const Line2D &line) const
{
	return a == line.a && b == line.b && c == line.c;
}

/// <Summary>
/// overload operation: "!=". simple compare, not normalize
/// </Summary>
bool Line2D::operator != (const Line2D &line) const
{
	return a != line.a || b != line.b || c != line.c;
}

/// <Summary>
/// Translation by 2D vector
/// </Summary>
void Line2D::Translation(const Vector2D &v)
{
	c = c - a * v.x - b * v.y;
}

/// <Summary>
/// sqrt(a ^ 2 + b ^ 2)
/// </Summary>
double Line2D::Norm() const
{
	return sqrt(a * a + b * b);
}

/// <Summary>
/// (a ^ 2 + b ^ 2)
/// </Summary>
double Line2D::Norm2() const
{
	return a * a + b * b;
}

/// <Summary>
/// Line Normalize
/// </Summary>
void Line2D::Normalize()
{
	if(a != 0)
	{
		if(a != 1)
		{
			c /= a;
			b /= a;
			a = 1;
		}
	}
	else if(b != 0)
	{
		c /= b;
		b = 1;
	}
}

/// <Summary>
/// get the line angle with the forward direction of X axis: [0, PI)
/// </Summary>
double Line2D::Angle() const
{
	if(a == 0) return 0;
	if(b == 0) return PI / 2;
	double tan = - a / b;
	if(tan > 0)
	{
		return atan(tan);
	}
	else
	{
		return atan(tan) + PI;
	}
}

/// <Summary>
/// get horizontal vector of 2D line
/// </Summary>
Vector2D Line2D::Horizontal(bool unit) const
{
	Vector2D ret(b, -a);
	if(unit == true)
	{
		ret.Normalize();
	}
	return ret;
}

/// <Summary>
/// get vertical vector of 2D line
/// </Summary>
Vector2D Line2D::Vertical(bool unit) const
{
	Vector2D ret(a, b);
	if (unit == true)
	{
		ret.Normalize();
	}
	return ret;
}

/// <Summary>
/// get the Perpendicular which pass by a point
/// </Summary>
Line2D Line2D::Perpendicular(const Point2D &p) const
{
	return Line2D(b, -a, a * p.y - b * p.x);
}


/// <Summary>
/// rotate counter clockwise around a point (radian)
/// </Summary>
void Line2D::Rotation(const Point2D &center, double angle)
{
	double _cos = cos(angle);
	double _sin = sin(angle);
	double _a = a * _cos - b * _sin;
	double _b = a * _sin + b * _cos;
	double _c = a * (center.x - center.x * _cos - center.y * _sin) + b * (center.y + center.x * _sin - center.y * _cos) + c;
	a = _a;
	b = _b;
	c = _c;
}

/// <Summary>
/// get the value of line expression
/// </Summary>
double Line2D::Evaluation(const Point2D &p) const
{
	return a * p.x + b * p.y + c;
}